package com.zisuyi.game.sdk.base.net

import android.widget.Toast
import androidx.lifecycle.LiveData
import com.weilele.mvvm.base.helper.*
import com.weilele.mvvm.utils.activity.toast
import kotlinx.coroutines.suspendCancellableCoroutine
import retrofit2.*
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException


/**
 * 会抛出异常
 */
suspend fun <T : Any> Call<T>.awaitCall(): T {
    return suspendCancellableCoroutine { continuation ->
        continuation.invokeOnCancellation {
            cancel()
        }
        enqueue(object : Retrofit2Call<T>() {
            override fun onSuccess(result: T) {
                continuation.resume(result)
            }

            override fun onError(t: Throwable, errorCode: Int?) {
                continuation.resumeWithException(t)
            }
        })
    }
}

/**
 * retrofit请求，添加统一的结果回调
 * 方便统一处理
 * 需要自己调用success方法
 */
inline fun <T, P> LiveData<StatusValue<P>>.retrofitTransform(isToastError: Boolean = true/*是否toast出错误*/,
                                                             isKeepLastValue: Boolean = false/*是否保留之前已经赋值的数据*/,
                                                             noinline errorCall: ((Throwable) -> T?)? = null,
                                                             call: () -> T?): T? {
    this.running(isKeepLastValue)
    return withError(
            errorCall = {
                this.error(it.message
                        ?: "createOkHttpCall Error", isKeepLastValue, null, null).apply {
                    if (isToastError) {
                        this.nonNullMsg.toast(Toast.LENGTH_LONG)
                    }
                }
                errorCall?.invoke(it)
            }, call = call)
}

/**
 * retrofit请求，添加统一的结果回调
 * 方便统一处理
 * 需要自己调用success方法
 */
inline fun <T> LiveData<StatusValue<T>>.retrofitRequest(
        isToastError: Boolean = true/*是否toast出错误*/,
        isKeepLastValue: Boolean = false/*是否保留之前已经赋值的数据*/,
        noinline errorCall: ((Throwable) -> T?)? = null,
        call: () -> T?): T? {
    this.running(isKeepLastValue)
    return withError(
            errorCall = {
                this.error(it.message
                        ?: "createOkHttpCall Error", isKeepLastValue, null, null).apply {
                    if (isToastError) {
                        this.nonNullMsg.toast(Toast.LENGTH_LONG)
                    }
                }
                errorCall?.invoke(it)
            },
            resultCall = {
                if (it != null) {
                    this.success(it, isKeepLastValue)
                } else {
                    this.error("result is null", isKeepLastValue)
                }
            }, call = call)
}


/**
 * 提供一个快速创建SimpleLiveDataCall的方法
 */
inline fun <reified P> LiveData<StatusValue<P>>.createRetrofitCall(
        isToastError: Boolean = true/*是否toast出错误*/,
        isKeepLastValue: Boolean = false/*是否保留之前已经赋值的数据*/,
        noinline resultCall: Function1<P, Unit>? = null/*结果回调，如果不为null，则LiveBean不走SUCCESS状态，需要自己手动处理*/
): Retrofit2Call<P> {
    this.running(isKeepLastValue)
    return object : Retrofit2Call<P>() {
        override fun onError(t: Throwable, errorCode: Int?) {
            t.printStackTrace()
            this@createRetrofitCall.error(t.message
                    ?: "createOkHttpCall Error", isKeepLastValue, null, errorCode).apply {
                if (isToastError) {
                    this.nonNullMsg.toast(Toast.LENGTH_LONG)
                }
            }
        }

        override fun onSuccess(result: P) {
            if (resultCall != null) {
                resultCall.invoke(result)
            } else {
                this@createRetrofitCall.success(result)
            }
        }
    }
}

/**
 * retrofit请求回调
 *
 */
abstract class Retrofit2Call<T> : Callback<T> {

    override fun onFailure(call: Call<T>, t: Throwable) {
        onError(t, null)
    }

    override fun onResponse(call: Call<T>, response: Response<T>) {
        if (response.isSuccessful) {
            val body = response.body()
            if (body == null) {
                val invocation = call.request().tag(Invocation::class.java)!!
                val method = invocation.method()
                val e = KotlinNullPointerException("Response from " +
                        method.declaringClass.name +
                        '.' +
                        method.name +
                        " was null but response body type was declared as non-null")
                onError(e, response.code())
            } else {
                onSuccess(body)
            }
        } else {
            onError(HttpException(response), response.code())
        }
    }

    //请求成功
    abstract fun onSuccess(result: T)

    //请求失败
    abstract fun onError(t: Throwable, errorCode: Int?)
}


